﻿using System;
using Missbot.Common;
using Missbot.Service;
using Newtonsoft.Json;

namespace Missbot.Core.Cache
{
    /// <summary>
    /// 快速缓存器
    /// </summary>
    public class RapidCacher
    {
        private static ILogSvc ILogSvc => AutofacSvc.Resolve<ILogSvc>();

        /// <summary>
        /// 读取/设置缓存
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="cacheKey"></param>
        /// <param name="expirySpan"></param>
        /// <param name="refreshFunc"></param>
        /// <returns></returns>
        public static TResult GetCache<TResult>(string cacheKey, TimeSpan expirySpan, Func<TResult> refreshFunc) where TResult : class
        {
            try
            {
                var cache = RCacheDA.Get(cacheKey);
                TResult result;
                if (cache == null)
                {
                    result = refreshFunc();
                    SetCache(cacheKey, result, expirySpan);
                }
                else
                {
                    result = JsonConvert.DeserializeObject<TResult>(cache.Value);
                }

                return result;
            }
            catch (Exception ex)
            {
                ILogSvc.LogError(ex);
                return default;
            }
        }

        /// <summary>
        /// 读取/设置缓存
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="expiryTime"></param>
        /// <param name="refreshFunc"></param>
        /// <typeparam name="TResult"></typeparam>
        /// <returns></returns>
        public static TResult GetCache<TResult>(string cacheKey, DateTime expiryTime, Func<TResult> refreshFunc) where TResult : class
        {
            return GetCache(cacheKey, expiryTime - DateTime.Now, refreshFunc);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="cacheValue"></param>
        /// <param name="expirySpan"></param>
        public static void SetCache(string cacheKey, object cacheValue, TimeSpan expirySpan)
        {
            SetCache(cacheKey, cacheValue, DateTime.Now.Add(expirySpan));
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="cacheValue"></param>
        /// <param name="expiryTime"></param>
        public static void SetCache(string cacheKey, object cacheValue, DateTime expiryTime)
        {
            var cache = RCacheDA.Get(cacheKey);
            if (cache == null)
            {
                cache = new RCache { Key = cacheKey, Value = JsonConvert.SerializeObject(cacheValue), ExpiryTime = expiryTime };
                cache.Insert();
                return;
            }

            cache.Value = JsonConvert.SerializeObject(cacheValue);
            cache.ExpiryTime = expiryTime;
            cache.Update();
        }

        /// <summary>
        /// 获取布尔类型的快速缓存
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public static bool GetBool(string cacheKey)
        {
            var cache = RCacheDA.Get(cacheKey);
            if (cache == null)
            {
                return false;
            }

            return bool.TryParse(cache.Value, out var result) && result;
        }

        /// <summary>
        /// 设置布尔类型的快速缓存
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="cacheValue"></param>
        /// <param name="expiryTime"></param>
        public static void SetBool(string cacheKey, bool cacheValue, DateTime expiryTime)
        {
            var cache = RCacheDA.Get(cacheKey);
            if (cache == null)
            {
                cache = new RCache { Key = cacheKey, Value = cacheValue.ToString(), ExpiryTime = expiryTime };
                cache.Insert();
                return;
            }

            cache.Value = cacheValue.ToString();
            cache.ExpiryTime = expiryTime;
            cache.Update();
        }
    }

    /// <summary>
    /// 缓存模型
    /// </summary>
    public class RCache : DbBaseEntity
    {
        /// <summary>
        /// 缓存键
        /// </summary>
        public string Key { get; init; }

        /// <summary>
        /// 缓存值（序列化后）
        /// </summary>
        public string Value { get; set; }

        /// <summary>
        /// 过期时间
        /// </summary>
        public DateTime ExpiryTime { get; set; }

        /// <summary>
        /// 是否在有效期内
        /// </summary>
        public bool IsInTime => ExpiryTime > DateTime.Now;
    }

    public static class RCacheDA
    {
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="Key"></param>
        /// <returns></returns>
        public static RCache Get(string Key)
        {
            return MongoService<RCache>.GetOnly(p => p.Key == Key);
        }

        /// <summary>
        /// 插入缓存
        /// </summary>
        public static void Insert(this RCache entity)
        {
            MongoService<RCache>.Insert(entity);
        }

        /// <summary>
        /// 更新缓存
        /// </summary>
        public static void Update(this RCache entity)
        {
            MongoService<RCache>.Update(entity);
        }
    }
}